#ifndef CONCRETEOBSERVEREXAMPLE_H
#define CONCRETEOBSERVEREXAMPLE_H

#include "Observer.h"
#include "Observable.h"
#include "UpdateInfo.h"

#include <string>

/**
 * Creamos un simple ejemplo bastante abstracto para
 * poder testear el patron observador.
 *
 * Necesitamos hacer esto puesto que el patron
 * observador se basa en clases abstractas y es
 * imposible instanciar este tipo de clases.
 */

/**
 * Enumeracion que mantiene todos los posibles cambios.
 */
enum ConcreteUpdateInfo
{
    Prop1Changed = 1,
    Prop2Changed
};

/**
 * Clase observable que contiene dos propiedades.
 *
 * Cada vez que el valor de alguna de sus propiedades
 * cambia, la clase se encarga de notificar a los
 * observadores.
 *
 * Notese el hecho de que el informar el cambio de
 * la segunda propiedad se hace atravez de la
 * extencion de la clase UpdateInfo.
 */
class ConcreteObservable : public Observable
{
public:
    void setProp1(bool prop1);
    bool prop1() const;

    void setProp2(bool prop2);
    bool prop2() const;

private:
    bool _prop1 = false;
    bool _prop2 = false;
};

/**
 * Esta clase extiende la informacion sobre
 * el cambio de alguna propiedad, en este caso
 * almacena el nuevo valor de la segunda propiedad.
 */
class ConcreteChanged : public UpdateInfo
{
public:
    ConcreteChanged(bool prop2Value, int type);

    bool prop2() const;

private:
    bool _prop2;
};

/**
 * Clase observadora que actualiza sus propiedades
 * dependiendo de los cambios que ocurran en el
 * objeto que observa.
 *
 * Esta clase es capaz de identificar todos los
 * cambios y actuar adecuadamente para todos ellos.
 */
class ConcreteObserver : public Observer
{
public:
    virtual void update(Observable *observable,
                        const UpdateInfo &info) override;

    std::string prop1() const;
    std::string prop2() const;

private:
    std::string _prop1 = "false";
    std::string _prop2 = "false";
};

#endif // CONCRETEOBSERVEREXAMPLE_H
